<template>
  <div class="ele-gallery" v-if="source">
    <!-- 预览图 -->
    <ul class="el-upload-list el-upload-list--picture-card">
      <li
        @click="handlePreview(index, source)"
        v-for="(source, index) of computedSources"
        :key="index"
        class="el-upload-list__item pointer"
      >
        <slot v-bind="{ source: source, index: index }">
          <el-image
            class="el-upload-list__item-thumbnail"
            :lazy="lazy"
            :src="source.thumb"
            :style="computedStyle"
            fit="cover"
            v-if="source.type === 'image'"
          />
          <video :src="source.thumb" :style="computedStyle" v-else-if="source.type === 'video'"></video>
          <div
            :style="computedStyle"
            class="ele-gallery-iframe embed-responsive embed-responsive-16by9"
            v-else-if="source.type === 'iframe'"
          >
            <iframe
              :src="source.thumb"
              allowfullscreen="true"
              border="0"
              frameborder="no"
              framespacing="0"
              scrolling="no"
            ></iframe>
          </div>
        </slot>
        <span v-if="isShowBtn" class="el-upload-list__item-actions">
          <div class="icon-list">
            <el-icon @click.stop="handlePreview(index, source)" class="pointer el-upload-list__item-preview">
              <ZoomIn />
            </el-icon>
            <span class="el-upload-list__item-delete" @click.stop="handleRemove(index)" v-if="isShowDelete && isShowUploadIcon">
              <el-icon><Delete /></el-icon>
            </span>
            <el-icon @click.stop="handleDownload(source)" class="pointer el-upload-list__item-download">
              <Download />
            </el-icon>
          </div>
          <el-tooltip :content="source.title">
            <p class="gallery-source-title overflow-ellipsis">{{ source.title }}</p>
          </el-tooltip>
          <slot name="action" v-bind="{ source: source, index: index }" />
        </span>
      </li>
    </ul>

    <preview-file v-if="openFile" v-model:open="openFile" :url="currentUrl" />
  </div>
</template>

<script setup name="ele-gallery">
  import PreviewFile from '@/components/PreviewFile';

  const { proxy } = getCurrentInstance();

  const props = defineProps({
    // 类型(支持图片, 视频, iframe)
    type: {
      type: String,
      default: 'image',
      validator(value) {
        return ['image', 'video', 'iframe'].includes(value);
      },
    },
    // 缩略图大小, 宽 === 高时, 简略写法
    size: Number,
    // 缩略图宽度, 当给定width时, 会覆盖size的值
    width: Number,
    // 缩略图高度, 当给定height时, 会覆盖size值
    height: Number,
    // 缩略图是否懒加载
    lazy: {
      type: Boolean,
      default: false,
    },
    // 源
    source: [String, Array, Object],
    // 缩略图后缀
    // 当type为image时, 且未指定thumb, 可通过thumbSuffix设置缩略图
    thumbSuffix: String,
    // 缩略图样式
    thumbStyle: Object,
    // 轮播图属性
    carouselAttrs: Object,
    // 删除函数
    removeFn: Function,
    // 统一的弹框标题
    title: String,
    // 强制多张图片按照单张显示
    sliceSingle: {
      type: Boolean,
      default: false,
    },
    // 是否显示按钮
    isShowBtn: {
      type: Boolean,
      default: true,
    },
    //是否显示上传按钮
    isShowUploadIcon: {
      type: Boolean,
      default: true,
    },
    isShowDelete: {
      type: Boolean,
      default: true,
    },
  });
  const {
    type,
    size,
    width,
    height,
    lazy,
    source,
    thumbSuffix,
    thumbStyle,
    carouselAttrs,
    removeFn,
    downloadFn,
    title,
    sliceSingle,
    isShowUploadIcon,
  } = toRefs(props);

  const data = reactive({
    openFile: false,
    currentUrl: '',
  });

  const { openFile, currentUrl } = toRefs(data);

  const computedStyle = computed(() => {
    let width = props.width || props.size;
    let height = props.height || props.size;
    if (props.type === 'image') {
      width = width ? width + 'px' : '150px';
      height = height ? height + 'px' : '150px';
    } else if (props.type === 'video') {
      width = width ? width + 'px' : '360px';
      height = height ? height + 'px' : 'auto';
    } else if (props.type === 'iframe') {
      width = width ? width + 'px' : '360px';
      height = height ? height + 'px' : 'auto';
    }

    return Object.assign({}, { width, height, display: 'block' }, props.thumbStyle);
  });

  const thumbs = computed(() => {
    return computedSources.value.map(item => {
      return item.thumb;
    });
  });

  const computedSources = computed(() => {
    const sources = props.source;
    if (typeof sources === 'string') {
      // 传入参数为 string
      return [getStringSource(sources)];
    } else if (sources instanceof Array) {
      // 传入参数为 array, 数据里面既可以有string 又可以有 object
      const res = [];
      sources.forEach(item => {
        if (item instanceof Object) {
          res.push(getObjectSource(item));
        } else if (typeof item === 'string') {
          res.push(getStringSource(item));
        } else {
          console.warn('数组元素错误', sources, item);
        }
      });
      return res;
    } else if (sources instanceof Object) {
      // 传入参数为 object
      return [getObjectSource(sources)];
    } else {
      return [];
    }
  });

  const getFileExtension = urlStr => {
    let fileExtension = '';
    if (urlStr.lastIndexOf('.') > -1) {
      fileExtension = urlStr.slice(urlStr.lastIndexOf('.') + 1);
      fileExtension = fileExtension.toLowerCase();
    }
    return fileExtension;
  };
  // 点击查看
  const handlePreview = (index, source) => {
    if (['.zip', '.rar'].includes(getFileExtension(source.src))) {
      proxy.$modal.msgError('zip,rar等压缩文件不能直接查看，请下载后查看！');
    } else {
      data.currentUrl = source.src;
      data.openFile = true;
    }
  };
  const handleRemove = index => {
    props.removeFn(index);
  };
  const handleDownload = source => {
    proxy.download('/resource/oss/download/' + source.id, {}, source.name);
  };
  // 获取字符串形式来源
  const getStringSource = src => {
    let thumb = src;
    if (props.type === 'image' && props.thumbSuffix) {
      thumb += props.thumbSuffix;
    }
    return {
      type: props.type,
      src: src,
      thumb: thumb,
    };
  };
  // 获取对象形式来源
  const getObjectSource = source => {
    source.type = source.thumb ? 'image' : props.type;
    source.thumb = source.thumb || source.src;
    return source;
  };
</script>

<style lang="scss" scoped>
  .el-upload-list__item-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-content: center;
    box-sizing: border-box;
    .icon-list {
      margin-top: 20px;
      width: 100%;
      display: flex;
      justify-content: space-evenly;
      align-items: flex-end;
    }
    .gallery-source-title {
      width: 100%;
      padding: 0 10px;
    }
  }

  /* 文本溢处打点 */
  .overflow-ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .ele-gallery .el-upload-list--picture-card .el-upload-list__item {
    width: auto;
    height: auto;
    margin: 0 8px 8px 0;
    font-size: 0;
  }
  .ele-gallery-image {
    max-width: 100%;
    max-height: 100%;
  }

  .ele-gallery-iframe.embed-responsive {
    position: relative;
    display: block;
    height: 0;
    padding: 0;
    overflow: hidden;
  }
  .ele-gallery-iframe.embed-responsive .embed-responsive-item,
  .ele-gallery-iframe.embed-responsive iframe,
  .ele-gallery-iframe.embed-responsive embed,
  .ele-gallery-iframe.embed-responsive object,
  .ele-gallery-iframe.embed-responsive video {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 0;
  }
  .ele-gallery-iframe.embed-responsive-16by9 {
    padding-bottom: 56.25%;
  }
  .ele-gallery-iframe.embed-responsive-4by3 {
    padding-bottom: 75%;
  }
</style>
